/**
 * 根据指定的卡片模型分页获取树型数据
 * 
 * 生成树策略: 先加载CardR数据, 再递归扩展子级节点, 重复节点从根节点移除
 * 
 * Created by wbx on 2022/06/06
 * 
 * 输入参数:
 *   Card:       必需,     文本,          卡片名称
 *   Model:                数组,          字段名的数组. 可包含数据或索引的名称
 *   Filter:               对象数组,      用于匹配根节点的过滤条件. 格式为: [ [三元素数组], { and/or: [] } ] -- 
 *   Order:                键值对象,      排序列. 键:字符串,指定别名; 值:字符串,指定升序(asc)或降序(desc), 默认按记录时间倒序排列, 不存在记录时间时用ID排序
 *   PageSize:             数值           页面大小
 *   PageNo:               数值           页码
 *   Parent:     必需,     文本,          上级引用的名称
 *   FilterEx:             对象数组,      格式同Filter,用作扩展子节点时的过滤条件
 *   OrderEx:              键值对象,      格式同Order,用作扩展子节点时的排序条件
 *   Key:                  文本,          级联的字段名称, 默认为children
 * 输出参数:
 *   按照Key级联的记录数组
 */
(function ({ UID, Card, Model, Filter, Order, PageSize, PageNo, Parent, FilterEx = [], OrderEx, Key = 'children' }, headers) {
  // 验证用户
  if (!UID) throw Error("未授权的访问");

  // 加载根节点
  const result = A.job.CardR({ UID, Card, Model, Filter, Order, PageSize, PageNo }, headers);
  const root_ids = result.Rows.map(r => r.ID);
  const is_childs = [];

  // 逐级扩展子节点
  const load_child = (rows) => {
    if (rows.length === 0) return;
    const id_map = {};
    const ids = rows.map(r => {
      id_map[r.ID] = r;
      return r.ID;
    });

    const all_rows = [];
    while (ids.length > 0) {
      const _ids = ids.splice(0, 1000);
      const { Rows } = A.job.CardR({
        UID,
        Card,
        Model,
        Filter: [...FilterEx, [Parent, 'in', _ids]],
        Order: OrderEx ?? Order
      });
      Rows.forEach(r => {
        // 处理子节点已经存在于根节点中的情况
        if (root_ids.includes(r.ID)) {
          is_childs.push(r);
        }
        const pid = r[Parent];
        if (id_map[pid][Key]) {
          id_map[pid][Key].push(r);
        } else {
          id_map[pid][Key] = [r];
        }
        all_rows.push(r);
      });
    }

    load_child(all_rows);
  };
  load_child(result.Rows);

  // 过滤掉已经作为子节点的根节点
  if (is_childs.length > 0) {
    result.Rows = result.Rows.filter(r => !is_childs.find(c => c.ID === r.ID));
  }

  return result;
})